﻿using Common.Tool.DataTools;
using Serilog;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace Common.Communication
{
    /// <summary>
    /// SerialPort基类
    /// </summary>
    public abstract class SerialPortBase:Tool.LogBase
    {

        /// <summary>
        /// 当前串口
        /// </summary>
        protected SerialPort localPort { get; set; }
        /// <summary>
        /// 连接状态
        /// </summary>
        public bool IsConnected => localPort?.IsOpen ?? false;
        /// <summary>
        /// 设置使用的串口
        /// </summary>
        public SerialPortBase(string portName, int baudRate = 115200, Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.One, int timeout = 1000)
        {
            localPort = SerialPortManager.InitPort(portName, baudRate, parity, dataBits, stopBits, timeout);
        }
        /// <summary>
        /// 连接
        /// </summary> 
        /// <returns></returns>
        public Result Open()
        {
            var result = new Result();
            try
            {
                if (localPort?.IsOpen == false)
                {
                    lock (localPort)
                    {
                        AppendCommunication($"{localPort?.PortName}", "打开串口");
                        localPort.Open();
                        result.IsSucceed = localPort.IsOpen;
                        if (!result.IsSucceed)
                        {
                            result.Err = "打开串口失败";
                            AppendCommunication(localPort.PortName, result.Err);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                AppendErr(localPort?.ToString(), "打开串口失败", ex);
                if (localPort?.IsOpen ?? false) localPort?.Close();
                result.IsSucceed = false;
                result.Err = ex.Message;
                result.ErrCode = 408;
                result.Exception = ex;
            }
            return result.EndTime();
        }

        /// <summary>
        /// 关闭连接
        /// </summary>
        /// <returns></returns>
        public Result Close()
        {
            var result = new Result();
            try
            {
                if (localPort?.IsOpen == true)
                {
                    AppendCommunication($"{localPort?.PortName}", "关闭串口");
                    localPort.Close();
                }
            }
            catch (Exception ex)
            {
                AppendErr(localPort?.ToString(), "关闭串口失败", ex);
                result.IsSucceed = false;
                result.Err = ex.Message;
            }
            return result.EndTime();
        }

        /// <summary>
        /// 发送
        /// </summary>
        /// <returns></returns>
        protected virtual Result Write(byte[] command)
        {
            var result = new Result();
            try
            {
                var re = Open();
                if (re.IsSucceed == false)
                {
                    return re.EndTime();
                }
                result.Requst = DataConvert.ByteArrayToString(command);
                AppendCommunication(localPort.PortName,"->" + result.Requst);
                //发送命令
                localPort.Write(command, 0, command.Length);
            }
            catch (Exception ex)
            {
                AppendErr(localPort?.ToString(), "发送失败", ex);
                result.IsSucceed = false;
                result.Err = ex.Message;
            }
            return result.EndTime();
        }
        /// <summary>
        /// 读取
        /// </summary>
        /// <returns></returns>
        protected virtual Result<byte[]> ReadBytes()
        {
            Result<byte[]> result = new Result<byte[]>();
            try
            {
                DateTime beginTime = DateTime.Now;
                var re = Open();
                if (re.IsSucceed == false)
                {
                    return new Result<byte[]>(re, result.InitialTime);
                }
                var tempBufferLength = localPort.BytesToRead;
                //在(没有取到数据或BytesToRead在继续读取)且没有超时的情况，延时处理
                while ((localPort.BytesToRead == 0 || tempBufferLength != localPort.BytesToRead) && DateTime.Now - beginTime <= TimeSpan.FromMilliseconds(localPort.ReadTimeout))
                {
                    tempBufferLength = localPort.BytesToRead;
                    //延时处理
                    Thread.Sleep(20);
                }
                byte[] buffer = new byte[localPort.BytesToRead];
                var receiveFinish = 0;
                while (receiveFinish < buffer.Length)
                {
                    var readLeng = localPort.Read(buffer, receiveFinish, buffer.Length);
                    if (readLeng == 0)
                    {
                        result.IsSucceed = false;
                        result.Err = "连接被断开";
                        AppendCommunication(localPort?.PortName, result.Err);
                        return result.EndTime();
                    }
                    receiveFinish += readLeng;
                }
                if (buffer.Length == 0)
                {
                    result.IsSucceed = false;
                    result.Err = "返回超时";
                    AppendCommunication(localPort?.PortName, result.Err);
                    return result.EndTime();
                }
                result.Value = buffer;
                result.Response = DataConvert.ByteArrayToString(buffer);
                AppendCommunication(localPort?.PortName, "<-" + result.Response);
            }
            catch (Exception ex)
            {
                AppendErr(localPort?.ToString(), "读取返回失败", ex);
                result.IsSucceed = false;
                result.Err = ex.Message;
            }
            return result.EndTime();
        }

        /// <summary>
        /// 发送报文，并获取响应报文
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        protected virtual Result<byte[]> WriteThenRead(byte[] command, int wait = 20, bool tryagain = true)
        {
            Result<byte[]> result = new Result<byte[]>();
            Result<byte[]> _writeThenRead()
            {
                try
                {
                    //发送命令
                    var re = Write(command);
                    if (!re.IsSucceed)
                    {
                        return new Result<byte[]>(re, result.InitialTime);
                    }
                    Thread.Sleep(wait);
                    var re2 = ReadBytes();
                    re2.Requst = re.Requst;
                    //获取响应报文
                    return new Result<byte[]>(re2, result.InitialTime);
                }
                catch (Exception ex)
                {
                    result.IsSucceed = false;
                    result.Err = ex.Message;
                    result.AddErr2List();
                    return result.EndTime();
                }
            }
            //从发送命令到读取响应为最小单元，避免多线程执行串数据（可线程安全执行）
            lock (this)
            {
                result = _writeThenRead();
                if (!result.IsSucceed && tryagain)
                {
                    Thread.Sleep(100);
                    result = _writeThenRead();
                }
                return result;
            }

        }
        /// <summary>
        /// 发送
        /// </summary>
        /// <returns></returns>
        protected virtual Result Write(string command)
        {
            return Write(Encoding.UTF8.GetBytes(command));
        }
        /// <summary>
        /// 读取
        /// </summary>
        /// <returns></returns>
        protected virtual Result<string> ReadString()
        {
            var info = ReadBytes();
            if (info.IsSucceed)
                return new Result<string>(info, Encoding.UTF8.GetString(info.Value));
            return new Result<string>(info);
        }

        /// <summary>
        /// 发送报文，并获取响应报文
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        protected virtual Result<string> WriteThenRead(string command, int wait = 50, bool tryagain = false)
        {
            var info = WriteThenRead(Encoding.UTF8.GetBytes(command),wait,tryagain);
            if (info.IsSucceed)
                return new Result<string>(info, Encoding.UTF8.GetString(info.Value));
            return new Result<string>(info);
        }
    }
}
